'''
Created on 18/10/2012

@author: Barrios - Correa - Felippone
'''

from FileManager import FileManager
from Parser import yacc,lex
from Exceptions import MlgExtendedException,MlgMsgExc


def metalangue_tokens(sourceCode):
    '''Siendo sourceCode un str con codigo fuente de Metalangue, devuelve la 
       lista de tokens (como son construidos por PLY) que resultan del analisis 
       lexico.
       Si el codigo no es valido, se debe levantar una excepcion con el error
       correspondiente. 
    '''
    try:
        lex.lexer.input(sourceCode)
        token = lex.lexer.token()
        while token:
            yield token
            token = lex.lexer.token()
    except Exception as e:
        raise MlgExtendedException("Error on parsing metalangue code.","Error trying to get tokens.",e)

def metalangue_ast(sourceCode):
    '''Retorna el arbol de sintaxis abstracta que resulta del parsing del 
       codigo en el str sourceCode. Si el codigo no es valido se debe levantar 
       una excepcion con el error correspondiente.
    '''
    try:
        ast = yacc.parse(sourceCode)
        return ast 
    except Exception as e:
        raise MlgExtendedException("Error on parsing metalangue code.","Error trying to get the ast.",e)

def metalangue_compilation(sourceCode):
    '''Retorna el codigo objeto generado a partir del codigo fuente dado por 
       sourceCode. Ambos sourceCode y el resultado son de tipo str. Si el codigo
       no es valido se debe levantar una excepcion con el error correspondiente.
    '''
    try:
        ast = yacc.parse(sourceCode)
        generated_code = ast.build_parser()
        return generated_code
    except Exception as e:
        raise MlgExtendedException("Error on parsing metalangue code.","Error trying to get the generated python code.",e)

def metalangue_compileFile(sourceFile, objectFile):
    '''Levanta el codigo fuente de metalangue en el archivo sourceFile y escribe
       el codigo objeto generado en el archivo objectFile. Ambos argumentos 
       pueden ser rutas tanto absolutas como relativas. Si el codigo no es valido 
       se debe levantar una excepcion con el error correspondiente.
    '''
    fm = FileManager()
    readCode, inputfile = fm.read_file(sourceFile)
    if readCode == "OK":
        try:
            ast = yacc.parse(inputfile)
            generated_file = ast.build_parser()
            fm.write_Py(generated_file,objectFile)
        except Exception as e:
            raise MlgMsgExc("Error on parsing metalangue code.","Error trying to parse metalangue code from file.",e)
    else:
        raise MlgMsgExc("Error on parsing metalangue code.","Error loading input file: " + inputfile + ".")
    
    